/*
 * Created on 21.07.2006 by leck
 *
 */
package de.devisnik.shifting.impl;

import java.util.ArrayList;
import java.util.Hashtable;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;

import de.devisnik.shifting.IHole;
import de.devisnik.shifting.IPiece;
import de.devisnik.shifting.IPuzzle;
import de.devisnik.shifting.IPuzzleListener;
import de.devisnik.shifting.ShiftingEvent;

public class PuzzleCanvas extends Composite {

	private final IPuzzle itsPuzzle;
	private Control[][] itsPieces;
	private Hashtable/* <IPiece, Label> */itsPieceHash;
	private Image itsImage;
	private PieceShifter itsLabelShifter;
	private IPuzzleListener itsShiftingGameListener = new IPuzzleListener() {

		public void handleShifting(ShiftingEvent[] eventArray) {
			for (int i = 0; i < eventArray.length; i++) {
				handleShiftingEvent(eventArray[i]);
			}
		}

		private void handleShiftingEvent(ShiftingEvent event) {
			final Control label = (Control) itsPieceHash.get(event.getPiece());
			if (label.isDisposed()) {
				return;
			}
			Point oldPosition = event.getOldPosition();
			Point newPosition = event.getNewPosition();

			itsLabelShifter = new PieceShifter(label, 5, (newPosition.x - oldPosition.x)
					* itsButtonWidth, (newPosition.y - oldPosition.y)
					* itsButtonHeight, itsShiftingDelay, itsListeners);
			itsLabelShifter.shift();
		}
	};
	private int itsButtonWidth;
	private int itsButtonHeight;
	private ArrayList/* <IPuzzleCanvasListener> */itsListeners = new ArrayList/* <IPuzzleCanvasListener> */();
	private final int itsShiftingDelay;

	public PuzzleCanvas(IPuzzle puzzle, Image image, int shiftingDelay,
			Composite parent, int style) {
		super(parent, SWT.NO_REDRAW_RESIZE);
		itsPuzzle = puzzle;
		itsImage = image;
		itsShiftingDelay = shiftingDelay;
		createButtons();
		setBackground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
		addListener(SWT.Resize, new Listener() {

			public void handleEvent(Event event) {
				layoutButtons();
			}
		});
		itsPuzzle.addGameListener(itsShiftingGameListener);
	}

	// @Override
	public void dispose() {
		itsPuzzle.removeGameListener(itsShiftingGameListener);
		super.dispose();
	}

	private Image createSubImage(Image image, int posX,
			int posY) {
		Rectangle bounds = image.getBounds();
		Point gameSize = itsPuzzle.getSize();
		int unitX = bounds.width / gameSize.x;
		int unitY = bounds.height / gameSize.y;
		Image subImage = new Image(getDisplay(), unitX, unitY);
		GC gc = new GC(subImage);
		gc.drawImage(image, posX * unitX, posY * unitY, unitX, unitY, 0, 0,
				unitX, unitY);
		gc.setAlpha(20);
		gc.setForeground(getDisplay().getSystemColor(SWT.COLOR_BLACK));
		gc.drawRectangle(0, 0, unitX - 1, unitY - 1);
		gc.dispose();
		return subImage;
	}

	private void cancelShifting() {
		if (itsLabelShifter == null) {
			return;
		}
		itsLabelShifter.setCanceled();
		itsLabelShifter = null;
	}
	
	private void layoutButtons() {
		cancelShifting();
		Rectangle clientArea = getClientArea();
		Point gameSize = itsPuzzle.getSize();
		itsButtonWidth = clientArea.width / gameSize.x;
		itsButtonHeight = clientArea.height / gameSize.y;
		for (int y = 0; y < gameSize.y; y++) {
			for (int x = 0; x < gameSize.x; x++) {
				Control pieceLabel = itsPieces[x][y];
				if (pieceLabel == null) {
					continue;
				}
				pieceLabel.setSize(itsButtonWidth, itsButtonHeight);
				IPiece piece = (IPiece) pieceLabel.getData();
				Point position = piece.getPosition();
				pieceLabel.setLocation(position.x * itsButtonWidth, position.y
						* itsButtonHeight);
			}
		}
	}

	private void createButtons() {
		Point gameSize = itsPuzzle.getSize();
		itsPieceHash = new Hashtable/* <IPiece, Label> */();
		itsPieces = new Control[gameSize.x][gameSize.y];
		for (int y = 0; y < gameSize.y; y++) {
			for (int x = 0; x < gameSize.x; x++) {
				IPiece piece = itsPuzzle.getPieceAt(x, y);
				if (piece instanceof IHole) {
					continue;
				}

				Point homePosition = piece.getHomePosition();
				final Image image = createSubImage(itsImage, homePosition.x, homePosition.y);
				PieceCanvas pieceCanvas = new PieceCanvas(this, image);
				pieceCanvas.addDisposeListener(new DisposeListener() {

					public void widgetDisposed(DisposeEvent e) {
						
						image.dispose();
						
					}});
				itsPieceHash.put(piece, pieceCanvas);
				pieceCanvas.setData(piece);
				itsPieces[x][y] = pieceCanvas;
			}
		}
	}

	public static void main(String[] args) {
		final Display display = new Display();
		Shell shell = new Shell(display);
		shell.setLayout(new FillLayout());
		Image image = new Image(display, "images/Wasserlilien.jpg");
		final Puzzle puzzle = new Puzzle(12, 8);
		new PuzzleCanvas(puzzle, image, 20, shell, SWT.NONE);
		shell.setSize(600, 400);
		shell.open();

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}
		display.dispose();
	}

	public void addListener(IPuzzleCanvasListener listener) {
		itsListeners.add(listener);
	}

	public void removeListener(IPuzzleCanvasListener listener) {
		itsListeners.remove(listener);
	}

}
